package com.hwd.srb.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hwd.srb.base.dto.SmsDTO;
import com.hwd.srb.common.exception.Assert;
import com.hwd.srb.common.result.ResponseEnum;
import com.hwd.srb.common.util.LendNoUtils;
import com.hwd.srb.core.enmu.TransTypeEnum;
import com.hwd.srb.core.hfb.FormHelper;
import com.hwd.srb.core.hfb.HfbConst;
import com.hwd.srb.core.hfb.RequestHelper;
import com.hwd.srb.core.mapper.UserAccountMapper;
import com.hwd.srb.core.pojo.bo.TransFlowBO;
import com.hwd.srb.core.pojo.entity.UserAccount;
import com.hwd.srb.core.pojo.entity.UserInfo;
import com.hwd.srb.core.service.TransFlowService;
import com.hwd.srb.core.service.UserAccountService;
import com.hwd.srb.core.service.UserInfoService;
import com.hwd.srb.rabbitmq.RabbitService;
import com.hwd.srb.rabbitmq.constant.MQConst;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 用户账户 服务实现类
 * </p>
 *
 * @author 黄伟东/Victor
 * @since 2022-03-10
 */
@Service
@Slf4j
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private TransFlowService transFlowService;

    @Resource
    private RabbitService rabbitService;

    /**
     * 会员账号充值，返回汇付宝表单字符串
     *
     * @param chargeAmt 充值金额
     * @param userId    用户id
     * @return java.lang.String
     */
    @Override
    public String commitCharge(BigDecimal chargeAmt, Long userId) {

        UserInfo userInfo = userInfoService.getById(userId);

        //判断账户绑定状态
        Assert.notEmpty(userInfo.getBindCode(), ResponseEnum.USER_NO_BIND_ERROR);

        // 调用汇付宝api生成表单
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("agentId", HfbConst.AGENT_ID);
        paramMap.put("agentBillNo", LendNoUtils.getNo());// 充值单号
        paramMap.put("bindCode", userInfo.getBindCode());
        paramMap.put("chargeAmt", chargeAmt);
        paramMap.put("feeAmt", new BigDecimal("0"));

        paramMap.put("returnUrl", HfbConst.RECHARGE_RETURN_URL);// 前端地址跳转页面
        paramMap.put("notifyUrl", HfbConst.RECHARGE_NOTIFY_URL);// 后端地址异步通知，修改绑定状态
        paramMap.put("timestamp", RequestHelper.getTimestamp());

        paramMap.put("sign", RequestHelper.getSign(paramMap));// 验签参数

        String formStr = FormHelper.buildForm(HfbConst.RECHARGE_URL, paramMap);

        return formStr;
    }


    /**
     * 充值异步回调
     *
     * @param paramMap 充值异步回调参数
     */
    @Transactional
    @Override
    public void notifyReCharge(Map<String, Object> paramMap) {

        log.info("充值成功：" + JSONObject.toJSONString(paramMap));

        // 获取参数
        BigDecimal chargeAmt = new BigDecimal((String) paramMap.get("chargeAmt"));// 充值金额
        String bindCode = (String) paramMap.get("bindCode"); // 充值人绑定协议号
        String agentBillNo = (String) paramMap.get("agentBillNo"); // 充值订单号
        BigDecimal mchFee = new BigDecimal((String) paramMap.get("mchFee")); // 商户收取用户的手续费

        // 根据回调函数更新user_account表
        UserInfo userInfo = userInfoService.getByBindCode(bindCode);

        LambdaUpdateWrapper<UserAccount> updateWrapper = new LambdaUpdateWrapper<UserAccount>()
                .setSql("amount = amount + " + chargeAmt + ",freeze_amount = freeze_amount + " + mchFee)
                .eq(UserAccount::getUserId, userInfo.getId());
        baseMapper.update(null, updateWrapper);

        // 记录交易流水
//        System.out.println("记录本次交易流水");//TODO
        TransFlowBO transFlowBO = TransFlowBO.builder()
                .agentBillNo(agentBillNo)
                .bindCode(bindCode)
                .amount(chargeAmt)
                .transTypeEnum(TransTypeEnum.RECHARGE)
                .memo("充值")
                .build();
        transFlowService.saveTransFlow(transFlowBO);

        // 充值成功后，向rabbitMQ发送充值成功消息 TODO
        log.info("发送充值成功消息");
        sendChargeSuccess(userInfo.getMobile(), "恭喜充值成功");
    }

    /**
     * 根据userId 获取账户余额
     *
     * @param userId 用户id
     * @return java.math.BigDecimal
     */
    @Override
    public BigDecimal getAccountByUserId(Long userId) {

        BigDecimal account = new BigDecimal("0");

        LambdaQueryWrapper<UserAccount> queryWrapper = new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getUserId, userId);
        UserAccount userAccount = baseMapper.selectOne(queryWrapper);

        if (userAccount != null) {
            account = userAccount.getAmount();
        }

        return account;
    }

    /**
     * 根据userId获取账户信息
     *
     * @param userId 用户id
     * @return com.hwd.srb.core.pojo.entity.UserAccount
     */
    @Override
    public UserAccount getUserAccountByUserId(Long userId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<UserAccount>().eq(UserAccount::getUserId, userId));
    }

    /**
     * 充值成功后，向rabbitMQ发送充值成功消息
     *
     * @param mobile  手机号
     * @param message 消息
     */
    private void sendChargeSuccess(String mobile, String message) {
        // 调用消息队列发送消息
        SmsDTO smsDTO = new SmsDTO();
        smsDTO.setMessage(message);
        smsDTO.setMobile(mobile);

        rabbitService.sendMessage(MQConst.EXCHANGE_TOPIC_SMS, MQConst.ROUTING_SMS_ITEM, smsDTO);
    }
}
